package com.jjiang.bbmall.auth.controller;

import com.alibaba.fastjson.TypeReference;
import com.jjiang.bbmall.auth.feign.MemberFeignService;
import com.jjiang.bbmall.auth.feign.ThirdPartFeignService;
import com.jjiang.common.vo.MemberEntityVo;
import com.jjiang.bbmall.auth.vo.UserLoginVo;
import com.jjiang.bbmall.auth.vo.UserRegistVo;
import com.jjiang.common.constant.AuthServerConstant;
import com.jjiang.common.exception.BizCodeEnumerate;
import com.jjiang.common.utils.R;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.data.redis.core.StringRedisTemplate;
import org.springframework.stereotype.Controller;
import org.springframework.validation.BindingResult;
import org.springframework.web.bind.annotation.GetMapping;
import org.springframework.web.bind.annotation.PostMapping;
import org.springframework.web.bind.annotation.RequestParam;
import org.springframework.web.bind.annotation.ResponseBody;
import org.springframework.web.servlet.mvc.support.RedirectAttributes;

import javax.servlet.http.HttpSession;
import javax.validation.Valid;
import java.util.HashMap;
import java.util.Map;
import java.util.UUID;
import java.util.concurrent.TimeUnit;


@Controller
public class LoginController {
    @Autowired
    ThirdPartFeignService thirdPartFeignService;
    @Autowired
    StringRedisTemplate redisTemplate;
    @Autowired
    MemberFeignService memberFeignService;

    private static final Integer validTime = 60 * 1000;

    @GetMapping("/sms/sendcode")
    @ResponseBody
    public R sendCode(@RequestParam("phone") String phone) {
        String key = AuthServerConstant.SMS_CODE_CACHE_PREFIX + phone;
        String redisCode = redisTemplate.opsForValue().get(key);
        long redisTime = 0;
        if (redisCode != null) {
            redisTime = Long.parseLong(redisCode.split("_")[1]);
        }
        // 1.redis缓存验证码，防止短时间【60s】内多次重复发送验证码
        if (System.currentTimeMillis() - redisTime < validTime) {
            // 在60s内，不能再发送
            return R.error(BizCodeEnumerate.SMS_CODE_EXCEPTION.getCode(), BizCodeEnumerate.SMS_CODE_EXCEPTION.getMsg());
        }

        String code = UUID.randomUUID().toString().substring(0, 5);

        String saveCode = code + '_' + System.currentTimeMillis();
        // 2.缓存验证码，方便后续进行验证码的再次校验。存入redis。key：sms:code:{phoneNum}; value：验证码
        redisTemplate.opsForValue().set(key, saveCode, 10, TimeUnit.MINUTES);

        R status = thirdPartFeignService.sendVerifyCode(phone, code);

        if (status.getCode() == 0) {
            return R.ok().put("verifyCode", status.get("verifyCode"));
        } else {
            return R.error();
        }
    }

    @PostMapping("/regist")
    public String registry(@Valid UserRegistVo vo, BindingResult result, RedirectAttributes redirectAttributes) {
        Map<String, String> errors = new HashMap<>();
        redirectAttributes.addFlashAttribute("errors", errors);
        if (result.hasErrors()) {
            result.getFieldErrors().stream().forEach(fieldError -> {
                if (!errors.containsKey(fieldError.getField())) {
                    errors.put(fieldError.getField(), fieldError.getDefaultMessage());
                }
            });

            // 用于模拟重定向携带数据，利用session原理；只要跳转到下个页面/取出数据之后，session中的数据就会删除掉。分布式中可能会有问题
            // 校验出错，重定向到注册页
            return "redirect:http://127.0.0.1:20000/reg.html";
        }
        // 注册，调用远程服务进行注册
        // 校验验证码
        String code = vo.getCode();
        String key = AuthServerConstant.SMS_CODE_CACHE_PREFIX + vo.getPhone();
        String redisCode = redisTemplate.opsForValue().get(key);
        String redisCodeInner = "";
        if (redisCode != null) {
            redisCodeInner = redisCode.split("_")[0];
        }
        if (!redisCodeInner.equals(code)) {
            errors.put("code", "验证码错误");
            // 校验出错，重定向到注册页
            return "redirect:http://127.0.0.1:20000/reg.html";
        }
        // 验证码校验提供，首先删除验证码
        redisTemplate.delete(key);
        // 调用注册接口
        R r = memberFeignService.regist(vo);
        if (r.getCode() != 0) {
            System.out.println("调用远程的注册接口失败");
            errors.put("msg", r.getData(new TypeReference<String>() {
            }));
            return "redirect:http://127.0.0.1:20000/reg.html";
        }

        // 回到登录页面
        return "redirect:http://127.0.0.1:20000/login.html";
    }

    @PostMapping("/login")
    public String login(UserLoginVo vo, RedirectAttributes redirectAttributes, HttpSession session) {
        // 13558931967
        // 123456
        // 进行远程调用，登录
        R r = memberFeignService.login(vo);
        if (r.getCode() == 0) {
            // 1. 第一次使用session；命令浏览器保存cookie信息
            // 子域名之间；设置可以使用cookie信息；
            // 子域进行添加session时，需要指定域名为父域名
            MemberEntityVo memberEntity = r.getData(new TypeReference<MemberEntityVo>() {
            });
            session.setAttribute(AuthServerConstant.LOGIN_USER, memberEntity);
            return "redirect:http://127.0.0.1:10000/";
        } else {
            Map<String, String> errors = new HashMap<>();
            redirectAttributes.addFlashAttribute("errors", errors);
            errors.put("msg", r.getData("msg", new TypeReference<String>() {
            }));
            return "redirect:http://127.0.0.1:20000/login.html";
        }
    }

    @GetMapping("/login.html")
    public String loginPage(HttpSession session) {
        // 查看是否登录过
        Object attribute = session.getAttribute(AuthServerConstant.LOGIN_USER);
        if (attribute == null) {
            // 没有登录
            return "login";
        } else {
            // 登录了
            return "redirect:http://127.0.0.1:10000/";
        }

    }
}
